import { Controller } from "../types"



export abstract class OrbitControlBase extends Controller {
	/**
	 * 是否启用缩放功能
	 */
	enableZoom: boolean = true
	/**
	 * 是否启用平移功能
	 */
	enablePan: boolean = true
	/**
	 * 是否启用旋转功能
	 */
	enableRotate: boolean = true
	/**
	 * 当前鼠标指针状态
	 */
	protected state: number = STATE.NONE
	/**
	 * 渲染器数据
	 */
	renderer?: Renderer
	// 摄像机目标点
	target: Vector3 = new Vector3()

	/**
	 
	 * @param pointerType 当前鼠标指针类型
	 */
	constructor(public pointerType: string) {
		super()
	}
	handler({ detail, renderer }: ChangeEvent) {
		this.renderer ||= renderer
		if (detail.pointerType !== this.pointerType) {
			return
		}

	}
	abstract update(): void
	abstract reset(): void
	abstract saveState(): void
	abstract down(event: PointerEventInfo): void
	abstract up(event: PointerEventInfo): void
	abstract move(event: PointerEventInfo): void
}
export class PointerOrbitControls extends OrbitControlBase {
	update(): void {
		throw new Error('Method not implemented.');
	}
	reset(): void {
		throw new Error('Method not implemented.');
	}
	saveState(): void {
		throw new Error('Method not implemented.');
	}
	
	down(event: PointerEventInfo): void {
		this.#onMouseDown(event)
	}
	up(event: PointerEventInfo): void {
		throw new Error('Method not implemented.');
	}
	move(event: PointerEventInfo): void {
		throw new Error('Method not implemented.');
	}
	constructor() {
		super('mouse')
	}
	#onMouseDown = (event: PointerEventInfo) => {
		const { offsetX, offsetY } = event
		let mouseAction: number;

		switch (event.button) {

			case 0:

				mouseAction = mouseButtons.LEFT;
				break;

			case 1:

				mouseAction = mouseButtons.MIDDLE;
				break;

			case 2:

				mouseAction = mouseButtons.RIGHT;
				break;

			default:

				mouseAction = - 1;

		}

		switch (mouseAction) {

			case MOUSE.DOLLY:

				if (!this.enableZoom) return;

				this.#downDolly(offsetX, offsetY);

				this.state = STATE.DOLLY;

				break;

			case MOUSE.ROTATE:

				if (event.ctrlKey || event.metaKey || event.shiftKey) {

					if (this.enablePan === false) return;

					this.#downPan(offsetX, offsetY);

					this.state = STATE.PAN;

				} else {

					if (this.enableRotate === false) return;

					this.#downRotate(offsetX, offsetY);

					this.state = STATE.ROTATE;

				}

				break;

			case MOUSE.PAN:

				if (event.ctrlKey || event.metaKey || event.shiftKey) {

					if (this.enableRotate === false) return;

					this.#downRotate(offsetX, offsetY);

					this.state = STATE.ROTATE;

				} else {

					if (this.enablePan === false) return;

					this.#downPan(offsetX, offsetY);

					this.state = STATE.PAN;

				}

				break;

			default:

				this.state = STATE.NONE;

		}


	}
	#downRotate = (offsetX: number, offsetY: number) => {

		this.#rotateStart.set(offsetX, offsetY);

	}

	#downDolly = (offsetX: number, offsetY: number) => {

		this.#updateZoomParameters(offsetX, offsetX);
		this.#dollyStart.set(offsetX, offsetY);

	}

	#downPan(offsetX: number, offsetY: number) {

		this.#panStart.set(offsetX, offsetY);

	}


	#handleMouseMoveRotate = (offsetX: number, offsetY: number) => {

		this.#rotateEnd.set(offsetX, offsetY);

		this.#rotateDelta.subVectors(this.#rotateEnd, this.#rotateStart).multiplyScalar(this.rotateSpeed);


		this.#rotateLeft(2 * Math.PI * this.#rotateDelta.x / this.clientHeight); // yes, height

		this.#rotateUp(2 * Math.PI * this.#rotateDelta.y / this.clientHeight);

		this.#rotateStart.copy(this.#rotateEnd);

		this.update();

	}

	#isTrackingPointer(pointerId: number) {
		return this.#pointers.some((p) => p === pointerId)
	}

	#handleMouseMoveDolly = (offsetX: number, offsetY: number) => {

		this.#dollyEnd.set(offsetX, offsetY);

		this.#dollyDelta.subVectors(this.#dollyEnd, this.#dollyStart);

		if (this.#dollyDelta.y > 0) {

			this.#dollyOut(this.#getZoomScale(this.#dollyDelta.y));

		} else if (this.#dollyDelta.y < 0) {

			this.#dollyIn(this.#getZoomScale(this.#dollyDelta.y));

		}

		this.#dollyStart.copy(this.#dollyEnd);

		this.update();

	}

	#handleMouseMovePan = (offsetX: number, offsetY: number) => {

		this.#panEnd.set(offsetX, offsetY);

		this.#panDelta.subVectors(this.#panEnd, this.#panStart).multiplyScalar(this.panSpeed);

		this.#pan(this.#panDelta.x, this.#panDelta.y);

		this.#panStart.copy(this.#panEnd);

		this.update();

	}

}
export class TouchOrbitControls extends OrbitControlBase {
	update(): void {
		throw new Error('Method not implemented.');
	}
	reset(): void {
		throw new Error('Method not implemented.');
	}
	saveState(): void {
		throw new Error('Method not implemented.');
	}
	down(event: PointerEventInfo): void {
		throw new Error('Method not implemented.');
	}
	up(event: PointerEventInfo): void {
		throw new Error('Method not implemented.');
	}
	move(event: PointerEventInfo): void {
		throw new Error('Method not implemented.');
	}

	constructor() {
		super('touch')
	}

}

